package top.dotgo.web.base.config.security;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.HandlerInterceptor;
import top.dotgo.kit.CfgKit;
import top.dotgo.kit.ContextKit;
import top.dotgo.kit.ex.DotException;
import top.dotgo.kit.ex.DotMsg;
import top.dotgo.web.base.R;
import top.dotgo.web.base.ex.GlobalExceptionHandler;
import top.dotgo.web.base.kit.JwtKit;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author : lin
 * @date : 2019/9/27 13:45
 * 安全 拦截器
 */
@Slf4j
public class SecurityInterceptor implements HandlerInterceptor {

    private static final String JAVAX_SERVLET_ERROR_STATUS_CODE = "javax.servlet.error.status_code";
    private static final String JAVAX_SERVLET_ERROR_MESSAGE = "javax.servlet.error.message";
    private static final String JAVAX_SERVLET_ERROR_EXCEPTION = "javax.servlet.error.exception";
    private static final String ERROR = "/error";

    /**
     * 输出到页面
     *
     * @param response response
     * @param r        r
     */
    public static void print(HttpServletResponse response, R r) {
        try (PrintWriter writer = response.getWriter()) {
            response.setStatus(DotMsg.SUCCESS_CODE);
            response.setContentType(SecurityFilter.APPLICATION_JSON_CHARSET_UTF_8);
            response.setHeader("Cache-Control", "no-cache, must-revalidate");
            writer.write(r.toString());
            writer.flush();
        } catch (IOException e) {
            log.error("print is err e={}", e.getMessage());
        }
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {


        //拦截 /error 请求 打印出错误信息
        if (request.getRequestURI().contains(ERROR)) {
            String msg = request.getAttribute(JAVAX_SERVLET_ERROR_MESSAGE).toString();
            Integer code = (Integer) request.getAttribute(JAVAX_SERVLET_ERROR_STATUS_CODE);
            if (StrUtil.isEmpty(msg)) {
                msg = request.getAttribute(JAVAX_SERVLET_ERROR_EXCEPTION) != null ? request.getAttribute(JAVAX_SERVLET_ERROR_EXCEPTION).toString() : "";
            }
            R r = R.err(code, msg);
            r = GlobalExceptionHandler.getMsg(r, new DotException(msg, code));
            print(response, r);
            return false;
        }

        //取token
        String token = request.getHeader(JwtKit.TOKEN);
        if (StrUtil.isEmpty(token)) {
            token = request.getParameter(JwtKit.TOKEN);
        }
        if (!StrUtil.isEmpty(token)) {
            JwtKit.getJwtBean(token);
        }

        //检查白名单
        for (String s : CfgKit.getIgnorePath()) {
            AntPathMatcher matcher = new AntPathMatcher();
            if (matcher.match(s, request.getRequestURI())) {
                return true;
            }
        }

        if (StrUtil.isEmpty(token)) {
            print(response, R.err(DotMsg.LOGIN_ERR, "token is empty"));
            return false;
        } else {
            R r = R.ok();
            try {
                //验证JWT的签名，返回CheckResult对象
                r = JwtKit.verify(token);
                if (r != null && !r.getCode().equals(DotMsg.SUCCESS_CODE)) {
                    print(response, r);
                    return false;
                }
            } catch (Exception e) {
                r.setCode(DotMsg.LOGIN_ERR);
                r.setMsg(e.getMessage());
                GlobalExceptionHandler.getMsg(r, e);
                print(response, r);
                return false;
            }

        }

        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ContextKit.clear();
        JwtKit.remove();
    }
}
